package pruebas.naves;

import org.junit.*;
import static org.junit.Assert.*;
import static modelo.SetUps.VELOCIDAD_AVIONETA;
import static modelo.SetUps.ENERGIA_AVIONETA;
import static modelo.SetUps.PUNTOS_AVIONETA;
import modelo.armas.Balas;
import modelo.armas.BalasEnemigas;
import modelo.armas.BandoAlgo42;
import modelo.armas.BandoEnemigo;
import modelo.armas.Laser;
import modelo.armas.PickUpEnergiaCaza;
import modelo.armas.RadarAlgo42;
import modelo.armas.RadarEnemigo;
import modelo.desplazadores.DesplazadorLineaRecta;
import modelo.naves.Avioneta;
import modelo.naves.EnergiaAgotadaException;
import modelo.naves.NaveAlgo42;
import modelo.util.Vector;

public class TestAvioneta {
	private Vector p1 = new Vector(0,10);//una posicion donde crear la nave
	private Vector p2 = new Vector (1,0);
	private Avioneta nave;

	@Before
	public void setUp() throws Exception {
		nave = new Avioneta(p1, p2);
	}

	@Test
	public void testInicializacion() {
		assertEquals("inicializacion incorrecta de posicion en nave",
				p1, nave.getPosicion());
		assertEquals("inicializacion incorrecta de posicion en nave",
				ENERGIA_AVIONETA, nave.getEnergia());
		assertEquals ("puntos incorrectos ",
				PUNTOS_AVIONETA, nave.getPuntos(0));
	}
	
	@Test
	public void testMovimiento() {
		DesplazadorLineaRecta desplazador = new DesplazadorLineaRecta(p1, p2,
				VELOCIDAD_AVIONETA);
		for (int i = 0; i < 5; i++) {
			nave.mover();
			desplazador.mover();
			assertEquals(
					"movimiento incorrecto en nave, al mover mas de una vez",
					desplazador.getPosicion(), nave.getPosicion());
		}
	}
	
	@Test (expected = EnergiaAgotadaException.class)
	public void testDanio(){
		//aplico a la nave un danio mayor a su energia
		nave.recibirDisparo(ENERGIA_AVIONETA + 5);
		assertEquals("energia en nave no se descuenta adecuadamente",
				(-5), nave.getEnergia());
		assertFalse("nave no debe permitir seguir actuando con su energia agotada",
				nave.seguirActuando());
		//al intentar moverse debe lanzar una excepcion
		nave.mover();
	}
	
	@Test
	public void testDisparar(){
		//debe devolver una bala enemiga de laser
		BalasEnemigas bala = (BalasEnemigas)nave.disparar();
		// para chequear esto la hago chocar con el algo42
		NaveAlgo42 algo42 = new NaveAlgo42 (p1, p2);
		bala.chocarCon(algo42);
		assertFalse ("disparo incorrecto",
				bala.seguirActuando());
	}
	
	/*
	 * como los test siguientes  se refieren a los metodos heredados de naves 
	 * autonomas solo se van a chequear en esta clase,
	 * pues en el resto de las clases herederas de naves autonomas 
	 * tendran el mismo comportamiento.
	 */
	
	@Test
	public void testColisionConNavesAutonomas(){
		Avioneta naveAutonoma = new Avioneta (p1,p2);
		//deben chocar espacialmente
		assertTrue ("deberian poder chocarse las dos naves",
				nave.chocaCon(naveAutonoma));
		nave.chocarCon(naveAutonoma);
		//pero no afectarse
		assertEquals ("no deberian afectarse dos naves autonomas",
				nave.getEnergia(), ENERGIA_AVIONETA);
		assertEquals ("no deberian afectarse dos naves autonomas",
				naveAutonoma.getEnergia(), ENERGIA_AVIONETA);
	}
	
	@Test
	public void testColisionConNaveAlgo42 (){
		NaveAlgo42 algo42 = new NaveAlgo42 (p1,p2);
		//deben chocar espacialmente
		assertTrue ("deberian poder chocarse las dos naves",
				nave.chocaCon(algo42));
		//ambas naves deben morir
		nave.chocarCon(algo42);
		assertFalse("el algo 42 no debe seguir actuando",
				algo42.seguirActuando());
		assertFalse ("la nave no debe seguir actuando",
				nave.seguirActuando());
	}
	
	@Test
	public void testColisionConBalaEnemiga (){
		//disparar una bala de laser enemigo
		Laser arma = new Laser (new BandoEnemigo());
		Balas bala = arma.disparar(p1, p2);
		//deben poder chocarse
		assertTrue ("la bala y la nave deben podeer chocarse",
				nave.chocaCon(bala));
		nave.chocarCon(bala);
		//no deben afectarse
		assertEquals ("la nave no debe verse afectada",
				ENERGIA_AVIONETA, nave.getEnergia());
		assertTrue ("la bala debe seguir actuando",
				bala.seguirActuando());
	}
	
	@Test
	public void testColisionConBalaAlgo42 (){
		//disparar una bala de laser de algo42
		Laser arma = new Laser (new BandoAlgo42());
		Balas bala = arma.disparar(p1, p2);
		//deben poder chocarse
		assertTrue ("la bala y la nave deben podeer chocarse",
				nave.chocaCon(bala));
		nave.chocarCon(bala);
		//deben afectarse
		assertTrue ("la nave debe verse afectada",
				nave.getEnergia() < ENERGIA_AVIONETA);
		assertFalse ("la bala no debe seguir actuando",
				bala.seguirActuando());
	}
	
	@Test
	public void testColisionConRadarEnemigo(){
		RadarEnemigo radar = new RadarEnemigo (p1, p2);
		//deben poder chocarse
		assertTrue ("el radar y la nave deben podeer chocarse",
				nave.chocaCon(radar));
		nave.chocarCon(radar);
		//no deben afectarse
		assertEquals ("la nave no debe verse afectada",
				ENERGIA_AVIONETA, nave.getEnergia());
		assertTrue ("el radar debe seguir actuando",
				radar.seguirActuando());
	}
	
	@Test
	public void testColisionConRadarAlgo42(){
		RadarAlgo42 radar = new RadarAlgo42 (p1, p2);
		//deben poder chocarse
		assertTrue ("el radar y la nave deben podeer chocarse",
				nave.chocaCon(radar));
		nave.chocarCon(radar);
		//deben afectarse
		assertEquals ("la nave no debe verse afectada",
				ENERGIA_AVIONETA, nave.getEnergia());
		assertFalse ("el radar no debe seguir actuando",
				radar.seguirActuando());
	}
	
	@Test
	public void testColisionConPickUps(){
		PickUpEnergiaCaza pickUp = new PickUpEnergiaCaza (p1, p2);
		//deben poder chocarse
		assertTrue ("el pickUp y la nave deben podeer chocarse",
				nave.chocaCon(pickUp));
		nave.chocarCon(pickUp);
		//deben afectarse
		assertEquals ("la nave no debe verse afectada",
				ENERGIA_AVIONETA, nave.getEnergia());
		assertFalse ("el pickUp no debe seguir actuando",
				pickUp.seguirActuando());
	}
}
